package com.leyou.order.service;

import com.leyou.common.auth.domain.UserHolder;
import com.leyou.common.constant.LyConstants;
import com.leyou.common.exception.domain.ExceptionEnum;
import com.leyou.common.exception.domain.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.domain.Order;
import com.leyou.order.domain.OrderDetail;
import com.leyou.order.domain.OrderLogistics;
import com.leyou.order.domain.OrderStatusEnum;
import com.leyou.order.dto.*;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PayHelper payHelper;

    public Long createOrder(CartToOrderDTO order) {
        try {
            //获取订单id
            Long orderId = idWorker.nextId();

            //创建订单对象
            Order orderData = new Order();
            orderData.setOrderId(orderId);
            orderData.setStatus(OrderStatusEnum.INIT.value());
            orderData.setPromotionIds(null);
            orderData.setInvoiceType(0);
            orderData.setPaymentType(1);
            orderData.setUserId(UserHolder.getId());
            orderData.setPostFee(0L);
            orderData.setSourceType(2);
            //得到提交的购物车集合
            List<CartDTO> carts = order.getCarts();
            //将列表结构的购物车对象集合，变成map结构
            Map<Long, Integer> cartMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
            //先得到skuId的集合
            List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
            //通过skuId的集合获取sku对象的集合
            List<SkuDTO> skuDTOS = itemClient.findSkusByIds(skuIds);
            //得到最终总金额
            Long totalFee = skuDTOS.stream()
                    .mapToLong(skuDTO -> skuDTO.getPrice() * cartMap.get(skuDTO.getId()))//收集到每件商品的金额
                    .sum();
            orderData.setTotalFee(totalFee);//每件商品的金额和数量相乘，最后相加
            orderData.setActualFee(1L);
            //保存订单
            orderMapper.insertSelective(orderData);

            //创建一个订单详情集合对象
            List<OrderDetail> orderDetails = new ArrayList<>();
            //变量订单中sku对象的集合
            skuDTOS.forEach(skuDTO -> {
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setId(idWorker.nextId());
                orderDetail.setOrderId(orderId);
                orderDetail.setSkuId(skuDTO.getId());
                orderDetail.setTitle(skuDTO.getTitle());
                orderDetail.setPrice(skuDTO.getPrice());
                orderDetail.setOwnSpec(skuDTO.getOwnSpec());
                orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));
                orderDetail.setNum(cartMap.get(skuDTO.getId()));
                orderDetail.setCreateTime(new Date());
                orderDetail.setUpdateTime(new Date());
                orderDetails.add(orderDetail);
            });
            //保存订单详情
            detailMapper.insertList(orderDetails);

            //保存物流
            AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getId(), orderId);
            //将dto转成domain
            OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
            orderLogistics.setOrderId(orderId);
            logisticsMapper.insertSelective(orderLogistics);

            //减库存
            itemClient.minusStock(cartMap);
            return orderId;
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

    }

    public OrderDTO findOrderById(Long id) {
        try {
            //根据id查询订单对象
            Order order = orderMapper.selectByPrimaryKey(id);
            //将对象转成dto
            OrderDTO orderDTO = BeanHelper.copyProperties(order, OrderDTO.class);

            //根据订单id查询出所有订单详情的集合
            OrderDetail record = new OrderDetail();
            record.setOrderId(order.getOrderId());
            List<OrderDetail> orderDetails = detailMapper.select(record);
            List<OrderDetailDTO> orderDetailDTOS = BeanHelper.copyWithCollection(orderDetails, OrderDetailDTO.class);

            orderDTO.setDetailList(orderDetailDTOS);

            //根据订单id查询物流信息
            OrderLogistics orderLogistics = logisticsMapper.selectByPrimaryKey(order.getOrderId());
            OrderLogisticsDTO orderLogisticsDTO = BeanHelper.copyProperties(orderLogistics, OrderLogisticsDTO.class);

            orderDTO.setLogistics(orderLogisticsDTO);
            return orderDTO;
        }catch (Exception e){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

    }

    public String getPayUrl(Long id) {
        //得到当前订单支付链接在redis中的key
        String payUrlKey = LyConstants.ORDER_PAY_URL_PRE+id;
        //先判断redis中是否有订单的支付链接
        Boolean hasKey = redisTemplate.hasKey(payUrlKey);
        if(hasKey){
            //如果有直接返回支付链接即可
            return redisTemplate.opsForValue().get(payUrlKey);
        }
        //根据订单id查询出订单对象
        Order order = orderMapper.selectByPrimaryKey(id);
        if(order==null){
            throw new LyException(502, "支付订单不存在！");
        }
        if(order.getStatus()!=OrderStatusEnum.INIT.value()){
            throw new LyException(502, "订单已支付！");
        }
        //如果没有发起微信统一下单请求
        String payUrl = payHelper.getPayUrl(id, order.getActualFee());
        //想reids中存放一份
        redisTemplate.opsForValue().set(payUrlKey, payUrl, 2, TimeUnit.HOURS);
        return payUrl;
    }

    public Integer queryStatus(Long id) {
        //根据id查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        //判空
        if(order==null){
            throw new LyException(502, "支付订单不存在！");
        }
        return order.getStatus();
    }

    public void checkNotifyResp(Map<String, String> resp) {
        log.info("【微信支付回调通知】开始!");
        //判断通信标识和业务标识
        payHelper.checkResp(resp);
        //获取订单号
        Long totalFee = Long.valueOf(resp.get("total_fee"));
        //获取金额
        Long orderId = Long.valueOf(resp.get("out_trade_no"));
        //根据订单id查询订单对象
        Order order = orderMapper.selectByPrimaryKey(orderId);
        //判断订单是否存在
        if(order==null){
            log.error("【微信支付回调通知】订单不存在！");
            throw new LyException(502, "【微信支付回调通知】订单不存在！");
        }
        //判断金额是否一致
        if(!order.getActualFee().equals(totalFee)){
            log.error("【微信支付回调通知】支付金额有误！");
            throw new LyException(502, "【微信支付回调通知】支付金额有误！");
        }
        //修改订单状态
        order.setStatus(OrderStatusEnum.PAY_UP.value());
        int count = orderMapper.updateByPrimaryKeySelective(order);
        if(count!=1){
            log.error("【微信支付回调通知】本地服务区修改订单状态异常！订单号为：{}",order.getOrderId());
        }
        log.info("【微信支付回调通知】结束!");
    }
}
